﻿using Abp.Runtime.Session;
using Abp.UI;
using Paas.Core.Approvals.Entities;
using Paas.Core.Approvals.Interfaces;
using Paas.Core.Const.Enums.Approvals;
using Paas.Core.Sys.Entities;
using Microsoft.EntityFrameworkCore;
using Basefr.Core;
using Basefr.Core.Consts.Enums;
using Basefr.Core.Entities;
using Basefr.Core.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Paas.Core.Approvals
{
    public class ApproveManager : CoreService, IApproveManager
    {
        private readonly IMainRepository<ApproveTemplate> _approveTemplateRepo;
        private readonly IMainRepository<Approve> _approveRepo;
        private readonly IMainRepository<ApproveStep> _approveStepRepo;
        private readonly IMainRepository<User, long> _userRepo;

        public ApproveManager(IMainRepository<Approve> approveRepo, IMainRepository<ApproveStep> approveStepRepo, IMainRepository<ApproveTemplate> approveTemplateRepo, IMainRepository<User, long> userRepo)
        {
            _approveRepo = approveRepo;
            _approveStepRepo = approveStepRepo;
            _approveTemplateRepo = approveTemplateRepo;
            _userRepo = userRepo;
        }

        public virtual Approve CreateApprove(EnumApproveType type, int objectId, List<KeyValuePair<int, long>> approverIds, out long? nextOperatorId)
        {
            var template = _approveTemplateRepo.GetAll()
                .Include(p => p.Steps).ThenInclude(p => p.Operators)
                .Include(p => p.Steps).ThenInclude(p => p.Next)
                .FirstOrDefault(p => p.Type == type);

            if (template == null || template.Steps.Count < 2)
            {
                throw new UserFriendlyException("审批流程尚未配置");
            }

            if (template.FirstStep.Operators.Any() && template.FirstStep.Operators.All(o => o.OperatorId != AbpSession.GetUserId()))
            {
                throw new UserFriendlyException("当前用户无权发起此流程");
            }

            var approve = new Approve
            {
                Template = template,
                Type = template.Type,
                ObjectId = objectId,
                ApplicantId = AbpSession.GetUserId(),
                State = EnumApproveState.Pending
            };
            _approveRepo.InsertAndGetId(approve);

            var step = new ApproveStep
            {
                Approve = approve,
                TemplateStep = template.FirstStep,
                Name = template.FirstStep.Name,
                SortIndex = template.FirstStep.SortIndex,
                OperatorId = AbpSession.GetUserId(),
                OperateTime = DateTime.Now,
                IsCurrent = false,
                State = EnumApproveStepState.Passed
            };
            _approveStepRepo.InsertAndGetId(step);

            var templateStep = template.FirstStep.Next;
            while (templateStep != null)
            {
                long approverId;
                if (approverIds.Any(p => p.Key == templateStep.Id))
                {
                    approverId = approverIds.First(p => p.Key == templateStep.Id).Value;

                    if (templateStep.Operators.All(o => o.OperatorId != approverId))
                    {
                        throw new UserFriendlyException("指定的审批人无效");
                    }
                }
                else
                {
                    throw new UserFriendlyException("未选择审批人");
                }

                var newStep = new ApproveStep
                {
                    Approve = approve,
                    TemplateStep = templateStep,
                    OperateByInitiator = templateStep.OperateByInitiator,
                    ChangeObjectState = templateStep.ChangeObjectState,
                    OperatorId = approverId,
                    Name = templateStep.Name,
                    SortIndex = templateStep.SortIndex,
                    IsCurrent = template.IsSecondStep(templateStep),
                    State = EnumApproveStepState.Pending
                };
                _approveStepRepo.InsertAndGetId(newStep);

                step.Next = newStep;

                step = newStep;
                templateStep = templateStep.Next;
            }

            nextOperatorId = approve.Steps.First().Next.OperatorId;

            return approve;
        }

        public virtual void ApproveFlow<T>(CreateApproveEntity<T> entity, int stepId, EnumApproveStepState state, string opinion, out EnumApproveState approveState, out bool isFinished, out long? nextOperatorId) where T : EntityBase
        {
            var step = _approveStepRepo.GetAll()
                .Include(p => p.Next)
                .Include(p => p.TemplateStep.Operators)
                .Include(p => p.Approve)
                .First(stepId);

            isFinished = step.IsLastStep();
            nextOperatorId = step.Next?.OperatorId;

            if (!step.IsCurrent || step.State != EnumApproveStepState.Pending)
            {
                throw new UserFriendlyException("审批流程节点无效，或已完成审批，请刷新页面后重试");
            }

            if (step.TemplateStep.Operators.All(o => o.OperatorId != AbpSession.GetUserId()))
            {
                throw new UserFriendlyException("当前用户无权执行此审批流程节点");
            }

            var currentUser = _userRepo.GetAll().Include(p => p.Roles).First(AbpSession.GetUserId());

            step.State = state;
            step.Opinion = opinion;
            step.Operator = currentUser;
            step.OperateTime = DateTime.Now;
            step.IsCurrent = false;

            //最后一步
            if (step.IsLastStep())
            {
                step.Approve.State = state == EnumApproveStepState.Failed ? EnumApproveState.Rejected : EnumApproveState.Passed;

                // 如果是最后一步，修改实体对象状态
                entity.ApproveState = step.Approve.State;
            }
            else //中间步骤
            {
                if (state == EnumApproveStepState.Failed)  //中间步骤驳回，直接中断整个流程，全部驳回
                {
                    step.Approve.State = EnumApproveState.Rejected;
                    entity.ApproveState = EnumApproveState.Rejected;

                    isFinished = true;
                }
                else
                {
                    step.Approve.State = EnumApproveState.OnGoing;
                    entity.ApproveState = EnumApproveState.OnGoing;

                    step.Next.IsCurrent = true;
                }
            }

            approveState = step.Approve.State;
        }

        public virtual void DeleteApprove(EnumApproveType type, int objectId)
        {
            var approve = _approveRepo.GetAll().Include(p => p.Steps).FirstOrDefault(p => p.Type == type && p.ObjectId == objectId);

            if (approve == null)
            {
                throw new UserFriendlyException("审批记录无效");
            }

            _approveStepRepo.Delete(approve.Steps);
            _approveRepo.Delete(approve);
        }
    }
}

